from lib.sys.logger_factory import LoggerFactory
from lib.sys.sys_config import SystemConfig
from crawler_core.constant.constants import Constants
from crawler_core.driver.driver_proxy import DriverProxy
from crawler_core.exception.aoount_exec import AccountException
from crawler_core.exception.vertify_exec import VertifyException
from login_server.utils.vertify_code_utils import VertifyCodeUtils
from login_server.interface_login import LoginInterface
from login_server.template.template_lagou import Propertylagou

import random
import time
from io import BytesIO
from PIL import Image, ImageFont, ImageDraw
from selenium.common.exceptions import TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class LoginLagou(LoginInterface):
    logger = LoggerFactory.getLogger("LoginLagou", "login")

    def __init__(self, context):
        self.url = Propertylagou.login_url
        self.driver = DriverProxy().get()
        self.wait = WebDriverWait(self.driver, 20)
        self.username = context[Constants.CONTEXT_USERNAME]
        self.password = context[Constants.CONTEXT_PASSWORD]
        pass

    def login(self, context):
        if self.driver:
            try:
                cookies = {}
            except VertifyException:
                raise VertifyException()
            except AccountException:
                raise AccountException()
            finally:
                self.driver.close()
        return cookies

    def open(self):
        """打开网页输入用户名密码并点击"""
        self.driver.delete_all_cookies()
        self.driver.get(self.url)
        self.driver.delete_all_cookies()
        self.driver.get(self.url)
        username = self.wait.until(
            EC.presence_of_element_located((By.XPATH, Propertylagou.input_username)))
        password = self.wait.until(
            EC.presence_of_element_located((By.XPATH, Propertylagou.input_password)))
        submit = self.wait.until(
            EC.element_to_be_clickable((By.XPATH, Propertylagou.input_submit)))
        username.send_keys(self.username)
        password.send_keys(self.password)
        time.sleep(1)
        submit.click()
        pass

    def password_error(self):
        """判断用户名或者密码是否错误"""
        try:
            return WebDriverWait(self.driver, 5).until(
                EC.text_to_be_present_in_element((By.ID, 'errorMsg'), '用户名或密码错误'))
        except TimeoutException:
            return False
        pass

    def login_successfully(self):
        """判断是否登录成功"""
        try:
            return bool(
                WebDriverWait(self.driver, 5).until(
                    EC.presence_of_element_located((By.CLASS_NAME, 'lg_os'))))
        except TimeoutException:
            return False
        pass

    def get_spider_position(self):
        """获取滑动验证码位置"""
        try:
            img = self.wait.until(EC.presence_of_element_located(
                (By.XPATH, Propertylagou.spider_img)))
        except TimeoutException:
            LoginLagou.logger.info('不是滑动验证码')
            # self.open()
        time.sleep(2)
        location = img.location
        size = img.size
        top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
            'width']
        return (top, bottom, left, right)
        pass

    def get_spider_screenshot(self):
        """获取网页截图"""
        screenshot = self.driver.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        return screenshot

    def get_spider_image(self):
        """获取验证码图片"""
        image_path = SystemConfig.get_p_screen_image_path()
        top, bottom, left, right = self.get_spider_position()
        LoginLagou.logger.info('验证码位置 %s,  %s, %s, %s,' % (top, bottom, left, right))
        screenshot = self.get_spider_screenshot()
        captcha = screenshot.crop((left, top, right, bottom))
        captcha.save(image_path +'lagouspider_image1.png')
        im = Image.open(image_path + "lagouspider_image1.png").convert("RGBA")
        font = ImageFont.truetype('ukai.ttc', 16)
        d = ImageDraw.Draw(im)
        d.text((0, 0), u'请点击凹槽左上角', (255, 0, 0), font=font)
        ImageDraw.Draw(im)
        im.save(image_path + "lagouspider_image2.png")
        time.sleep(5)

    def get_spider_distance(self):
        """获取滑动距离"""
        self.get_spider_image()
        im = open('lagouspider2.png', 'rb').read()

        result = VertifyCodeUtils.analysis(im, 9101)
        distance = int(result.get('pic_str').split(",")[0]) - 33
        LoginLagou.logger.info(distance)
        return distance

    def get_track(self):
        distance = self.get_spider_distance()
        track = []
        current = 0
        mid = distance * 4 / 5
        t = (random.randint(30, 50)) / 10.0
        v = 0
        while current < distance:
            if current < mid:
                a = random.randint(10, 20) / 10
            else:
                a = -random.randint(10, 30) / 10
            v0 = v
            v = v0 + a * t
            move = v0 * t + 1 / 2 * a * t * t
            current += move
            track.append(round(move))
        return track

    def move(self):
        """模拟滑动"""
        track = self.get_track()
        spider = self.wait.until(EC.presence_of_element_located(
            (By.XPATH, Propertylagou.spider_span)))
        action = ActionChains(self.driver)
        action.click_and_hold(spider).perform()
        for i in track:
            action.move_by_offset(xoffset=i, yoffset=0).perform()
        time.sleep(0.5)
        action.release().perform()
        time.sleep(0.2)
        # self.browser.close()

    def get_touch_element(self):
        """获取点触验证码对象"""
        try:
            img = self.wait.until(EC.presence_of_element_located(
                (By.XPATH, Propertylagou.touch_img)))
            return img
        except TimeoutException:
            LoginLagou.logger.info("不是点触验证码")
            # self.open()

    def get_touch_position(self):
        """获取点触验证码位置"""
        img = self.get_touch_element()
        location = img.location
        size = img.size
        top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
            'width']
        return (top, bottom, left, right)

    def get_touch_screenshot(self):
        """获取点触网页截图"""
        screenshot = self.driver.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        return screenshot

    def get_touch_image(self):
        """获取点触验证码图片"""
        image_path = SystemConfig.get_p_screen_image_path()
        top, bottom, left, right = self.get_touch_position()
        print('验证码位置', top, bottom, left, right)
        screenshot = self.get_touch_screenshot()
        captcha = screenshot.crop((left, top, right, bottom - 51.2))
        captcha.save(image_path + 'lagoutouch_image1.png')
        time.sleep(1)

    def get_touch_location(self):
        """获取点击位置"""
        self.get_touch_image()
        im = open('lagoutouch_image1.png', 'rb').read()
        result = VertifyCodeUtils.analysis(im, 9004)
        groups = result.get('pic_str').split('|')
        LoginLagou.logger.info(str(groups))
        locations = [[int(num) for num in group.split(',')] for group in groups]
        return locations

    def click(self):
        """模拟点击"""
        locations = self.get_touch_location()
        for location in locations:
            LoginLagou.logger.info(str(location))
            ActionChains(self.driver).move_to_element_with_offset(self.get_touch_element(), location[0],
                                                                   location[1]).click().perform()
            time.sleep(random.randint(1, 3))
        commit_element = self.wait.until(EC.presence_of_element_located(
            (By.XPATH, Propertylagou.touch_commit)))
        commit_element.click()
        time.sleep(0.5)
        # self.browser.close()

    def get_cookies(self):
        """获取cookeis"""
        self.driver.get(Propertylagou.cookie_url)
        return self.driver.get_cookies()
        pass

    def main(self):
        """破解入口"""
        self.open()
        if self.password_error():
            LoginLagou.logger.error("LoginLagou登录失败，账号密码有误...")
            raise VertifyException()
        # 如果不需要验证码直接登录成功
        if self.login_successfully():
            cookies = self.get_cookies()
            return cookies
        # 识别滑动验证码
        try:
            self.move()
        except:
            LoginLagou.logger.info("出现验证码")
            # 识别点触验证码
            try:
                self.click()
            except VertifyException:
                LoginLagou.logger.error("LoginLagou登录失败，验证码失败...")
                raise VertifyException()
        time.sleep(3)
        if self.login_successfully():
            cookies = self.get_cookies()
            return cookies
        else:
            LoginLagou.logger.info("登录失败")
        pass
